home *** CD-ROM | disk | FTP | other *** search
/ NeXTSTEP 3.3 (Developer)…68k, x86, SPARC, PA-RISC] / NeXTSTEP 3.3 Dev Intel.iso / NextDeveloper / Source / GNU / debug / Common / RegionManager.m < prev    next >
Text File  |  1994-11-29  |  12KB  |  450 lines

  1. #import "RegionManager.h"
  2. #import <stdlib.h>
  3. #import <string.h>
  4. #import <mach/mach.h>
  5. #import <mach-o/loader.h>
  6. #import <mach/vm_param.h>
  7.  
  8. kern_return_t static inline vmRegion(task_t task, 
  9.                      vm_address_t address,
  10.                      Region *region)
  11. {
  12.     vm_offset_t    offset;
  13.     vm_prot_t maxProtection;
  14.     vm_inherit_t inheritance;
  15.     boolean_t shared;
  16.     port_t objectName;
  17.     region->reloc.address = address;
  18.     return vm_region(task,
  19.                  ®ion->reloc.address,
  20.              ®ion->reloc.size,
  21.              ®ion->protection,
  22.              &maxProtection,
  23.              &inheritance,
  24.              &shared,
  25.              &objectName,
  26.              &offset);
  27. }
  28.  
  29. @implementation RegionManager
  30.  
  31. -initTask: (vm_task_t)theTask readInRegions: (BOOL)readInRegions
  32. {
  33.     vm_statistics_data_t vm_stats;
  34.     
  35.     task = theTask;
  36.     vm_statistics(theTask, &vm_stats);
  37.     pageSize = vm_stats.pagesize;
  38.     relocSize = sizeof(Region);
  39.     rmFlags.shouldSortRelocs = NO;
  40.     if (readInRegions)
  41.     [self readInAllRelocs];
  42.     else
  43.     rmFlags.invalid = YES;
  44.     return self;
  45. }
  46.  
  47. -(BOOL)isTask
  48. {
  49.     struct task_basic_info taskInfo;
  50.     unsigned int taskInfoCount;
  51.     BOOL ret;
  52.     
  53.     taskInfoCount = TASK_BASIC_INFO_COUNT;
  54.     ret = (task_info(task,
  55.                        TASK_BASIC_INFO,
  56.                (task_info_t)&taskInfo,
  57.                &taskInfoCount) == KERN_SUCCESS) ? YES : NO;
  58.     if (!ret && taskGoneCallBack)
  59.     (*taskGoneCallBack)();
  60.     return ret;
  61. }
  62.  
  63. -(void)setTaskGoneCallBack: (TaskGoneCallBack)theCallBack
  64. {
  65.     taskGoneCallBack = theCallBack;
  66. }
  67.  
  68. +newTask: (vm_task_t)theTask
  69. {
  70.     return [[super new] initTask: theTask readInRegions: YES];
  71. }
  72.  
  73. +newTask: (vm_task_t)theTask readInRegions: (BOOL)readInRegions
  74. {
  75.     return [[super new] initTask: theTask readInRegions: readInRegions];
  76. }
  77.  
  78. -invalidate
  79. {
  80.     if (rmFlags.invalid)
  81.     return self;
  82.     else {
  83.     Region *region;
  84.     int count;
  85.     if (relocs) {
  86.         for (count = numRelocs, region = (Region *)relocs;
  87.          count; 
  88.          count--, region++) {
  89.         if (region->reloc.rFlags.readIn)
  90.             vm_deallocate(task_self(),
  91.                   region->reloc.data,
  92.                   region->reloc.size);
  93.         }
  94.     }
  95.     if (pages) {
  96.         free(pages);
  97.         pages = NULL;
  98.     }
  99.     return [super invalidate];
  100.     }
  101. }
  102.  
  103. -(void)getStartPage: (void **)startPage andSize: (int *)sizePage
  104.          forPointer: (void *)start      andSize: (int)numBytes
  105. {
  106.     vm_address_t offset = ((vm_address_t)start % pageSize);
  107.     vm_address_t s = numBytes + offset;
  108.     
  109.     *startPage = start - offset;
  110.     *sizePage =  (s - (s % pageSize)) + pageSize;
  111. }
  112.         
  113. -(void)protectDataAt: (const void *)start for: (int)numBytes
  114. {
  115.     vm_address_t offset = ((vm_address_t)start % pageSize);
  116.     vm_address_t startPage = (vm_address_t)start - offset;
  117.     size_t sizePage = numBytes + offset;
  118.     
  119.     vm_protect(task, startPage, pageSize, NO, VM_PROT_READ);
  120. }
  121.  
  122. -(void)unProtectDataAt: (const void *)start for: (int)numBytes
  123. {
  124.     vm_address_t offset = ((vm_address_t)start % pageSize);
  125.     vm_address_t startPage = (vm_address_t)start - offset;
  126.     size_t sizePage = numBytes + offset;
  127.     
  128.     vm_protect(task, startPage, pageSize, NO, VM_PROT_READ | VM_PROT_WRITE);
  129. }
  130.  
  131. -(int)writeDataAt: (const void *)start for: (int)numBytes reloc: (Region *)region markOnly: (BOOL)markOnly
  132. {
  133.     vm_address_t offset = ((vm_address_t)start % pageSize);
  134.     vm_address_t startPage = (vm_address_t)start - offset;
  135.     size_t sizePage = numBytes + offset;
  136.     pointer_t startData;
  137.     kern_return_t ret = 0;
  138.     unsigned char *pPage;
  139.     
  140.     if (markOnly) {
  141.     if (!region->pagesInvalid)
  142.         regionsInvalid++;
  143.     }
  144.     for (sizePage += (pageSize - (sizePage % pageSize)),
  145.          startData = region->reloc.data
  146.                      + ((pointer_t)startPage - region->reloc.address),
  147.          pPage = region->pages
  148.              + (((pointer_t)startPage - region->reloc.address) / pageSize);
  149.          sizePage && !ret;
  150.      sizePage -= pageSize, startData += pageSize, startPage += pageSize,
  151.      pPage++) {
  152.     if (markOnly) {
  153.         if (!(*pPage & PAGEINVALID)) {
  154.         *pPage |= PAGEINVALID;
  155.         region->pagesInvalid++;
  156.         }
  157.     } else {
  158.         *pPage &= ~PAGEINVALID;
  159.         if (*pPage & VM_PROT_WRITE)
  160.         ret = vm_write(task, startPage, startData, pageSize);
  161.         else {
  162.         vm_protect(task, startPage, pageSize, NO, VM_PROT_WRITE);
  163.         ret = vm_write(task, startPage, startData, pageSize);
  164.         vm_protect(task, startPage, pageSize, NO,
  165.                 (vm_prot_t)(*pPage & 0x7));
  166.         }
  167.     }
  168.     }
  169.     if (ret == KERN_SUCCESS)
  170.     return numBytes;
  171.     else {
  172.     [self isTask];
  173.     return 0;
  174.     }
  175. }
  176.  
  177. -(int)writeDataAt: (const void *)start for: (int)numBytes reloc: (Region *)region
  178. {
  179.     return [self writeDataAt: start for: numBytes reloc: region markOnly: NO];
  180. }
  181.  
  182. -(int)putDataAt: (void *)start for: (int)numBytes from: (const void *)data markOnly: (BOOL)markOnly
  183. {
  184.     int numBytesInRegion;
  185.     Reloc *reloc = [self relocFor: start];
  186.     if (reloc) {
  187.         numBytesInRegion = reloc->maxAddress - (int)start;
  188.         if (numBytes > numBytesInRegion)
  189.         numBytes = numBytesInRegion;
  190.     if (numBytes == 1)
  191.         *(char *)(reloc->data + ((pointer_t)start - reloc->address))
  192.         = *(char *)data;
  193.     else
  194.         memcpy((void *)(reloc->data + ((pointer_t)start - reloc->address)),
  195.                data,
  196.            numBytes);
  197.     return [self writeDataAt: start for: numBytes  reloc: (Region *)reloc markOnly: markOnly];
  198.     } else
  199.     return 0;
  200. }
  201.  
  202. -(int)putDataAt: (void *)start for: (int)numBytes from: (const void *)data
  203. {
  204.     return [self putDataAt: start for: numBytes from: data markOnly: NO];
  205. }
  206.  
  207. -(void)flushMarkedPages
  208. {
  209.     int ret = 0;
  210.     while (regionsInvalid) {
  211.     int i;
  212.     Region *region;
  213.     
  214.     for (i = 0, region = (Region *)relocs;
  215.          i < numRelocs;
  216.          i++, ((void *)region) += relocSize) {
  217.         if (region->pagesInvalid) {
  218.         unsigned char *p = region->pages;
  219.         while (region->pagesInvalid) {
  220.             if (*p & PAGEINVALID) {
  221.             int numPage = p - region->pages;
  222.             pointer_t startPage, startData;
  223.             
  224.             startPage
  225.             = region->reloc.address + (numPage * pageSize);
  226.             startData
  227.             = region->reloc.data + (numPage * pageSize);
  228.             *p &= ~PAGEINVALID;
  229.             region->pagesInvalid--;
  230.             if (*p & VM_PROT_WRITE)
  231.                 ret = vm_write(task, startPage, startData, pageSize);
  232.             else {
  233.                 vm_protect(task, startPage, pageSize, NO, VM_PROT_WRITE);
  234.                 ret = vm_write(task, startPage, startData, pageSize);
  235.                 vm_protect(task, startPage, pageSize, NO,
  236.                     (vm_prot_t)(*p & 0x7));
  237.             }
  238.             }
  239.             p++;
  240.         }
  241.         regionsInvalid--;
  242.         }
  243.     }
  244.     }
  245.     if (ret) 
  246.     [self isTask];
  247. }
  248.  
  249. -(int)writeDataAt: (const void *)start for: (int)numBytes;
  250. {
  251.     Reloc *reloc = [self relocFor: start];
  252.     if (reloc)
  253.     return [self writeDataAt: start for: numBytes reloc: (Region *)reloc];
  254.     else
  255.     return NO;
  256. }
  257.  
  258. -(BOOL)readInReloc: (Reloc *)reloc
  259. {
  260.     kern_return_t ret;
  261.     unsigned int nData;
  262.     if (reloc->rFlags.readIn) {
  263.     return YES;
  264.     } else {
  265.     ret = vm_read(task, reloc->address, reloc->size, &reloc->data, &nData);
  266.     if (ret == KERN_SUCCESS) {
  267.         reloc->maxData = reloc->data + reloc->size;
  268.         reloc->displacement = reloc->data - reloc->address;
  269.         reloc->rFlags.readIn = YES;
  270.         return YES;
  271.     } else {
  272.         [self isTask];
  273.         return NO;
  274.     }
  275.     }
  276. }
  277.  
  278. -(void)combineRegions: (BOOL)combineRegions
  279. { dontCombineRegions = !combineRegions;}
  280.  
  281. -(void)_readInAllRelocs
  282. {
  283.     kern_return_t error = 0;
  284.     vm_address_t address = VM_MIN_ADDRESS;
  285.     Region *theRegion, *regions, *newRegion, *nextRegion, *lastRegion;
  286.     int count = 0, numPages = 0, numAlloced = 16, nPages;
  287.     unsigned char *thePage;
  288.     
  289.     if ([self isTask]) {
  290.     theRegion = regions = malloc(numAlloced * sizeof(Region));
  291.     bzero(regions, numAlloced * sizeof(Region));
  292.     while (!error) {
  293.         error = vmRegion(task, address, theRegion);
  294.         address = theRegion->reloc.address + theRegion->reloc.size;
  295.         if (!error) {
  296.         if (theRegion->protection & VM_PROT_READ) {
  297.             count++;
  298.             numPages += theRegion->reloc.size / pageSize;
  299.             if (count < numAlloced)
  300.             theRegion++;
  301.             else {
  302.             numAlloced *= 2;
  303.             regions = realloc(regions,
  304.                               numAlloced * sizeof(Region));
  305.             theRegion = regions + count;
  306.             bzero(theRegion, count * sizeof(Region));
  307.             }
  308.         }
  309.         if (address < theRegion->reloc.address)
  310.             error = KERN_NO_SPACE;
  311.         }
  312.     }
  313.     if (error == KERN_NO_SPACE) {
  314.         lastRegion = theRegion;
  315.     
  316.         pages = malloc(numPages);
  317.         for (theRegion = regions, thePage = pages;
  318.              theRegion < lastRegion;
  319.          theRegion++) {
  320.         theRegion->pages = thePage;
  321.         nPages = theRegion->reloc.size / pageSize;
  322.         while(nPages--)
  323.             *(thePage++) = (unsigned char)theRegion->protection;
  324.         }
  325.         
  326.         if (dontCombineRegions) {
  327.         for (theRegion = regions; theRegion < lastRegion; theRegion++)
  328.             theRegion->reloc.maxAddress
  329.             = theRegion->reloc.address + theRegion->reloc.size;
  330.         relocs = regions;
  331.         numRelocs = count;
  332.         } else {
  333.         relocs = malloc(count * sizeof(Region));
  334.         bzero(relocs, count * sizeof(Region));
  335.         for (theRegion = regions, newRegion = relocs;
  336.             theRegion < lastRegion;
  337.             theRegion = nextRegion, newRegion++) {
  338.             for (nextRegion = theRegion + 1;
  339.             (nextRegion < lastRegion
  340.             && ((theRegion->reloc.address + theRegion->reloc.size)
  341.                 == nextRegion->reloc.address));
  342.             nextRegion++) {
  343.             theRegion->reloc.size += nextRegion->reloc.size;
  344.             }
  345.             *newRegion = *theRegion;
  346.             newRegion->reloc.maxAddress
  347.             = newRegion->reloc.address + newRegion->reloc.size;
  348.         }
  349.         numRelocs = newRegion - (Region *)relocs;
  350.         relocs = realloc(relocs, numRelocs * sizeof(Region));
  351.         free(regions);
  352.         }
  353.         rmFlags.invalid = NO;
  354.     } else
  355.         free(regions);
  356.         
  357.     if (error != KERN_NO_SPACE) 
  358.         [self isTask];
  359.     } 
  360. }
  361.  
  362. -(struct mach_header *)getMachHeader
  363. {
  364.     Reloc *reloc;
  365.     int count;
  366.     struct mach_header *header, *foundHeader;
  367.  
  368.     if (rmFlags.invalid)
  369.     [self readInAllRelocs];
  370.     reloc = relocs;
  371.     for (foundHeader = NULL, count = 0;
  372.          !foundHeader && count < numRelocs;
  373.      count++) {
  374.     [self readInReloc: reloc];
  375.     header = [self pointerFor: (void *)reloc->address
  376.                      withSize: sizeof(*header)];
  377.     if (header
  378.         && (header->magic == MH_MAGIC)
  379.         && ([self pointerFor: (void *)reloc->address
  380.                     withSize: header->sizeofcmds]))
  381.         foundHeader = header;
  382.     else
  383.         ((void *)reloc) += relocSize;
  384.     }
  385.     return foundHeader;
  386. }
  387.  
  388. -(int)getNumMachHeaders
  389. {
  390.     struct mach_header *myHeader;
  391.     int numHeaders, i;
  392.     struct fvmlib_command *loadCmd;
  393.     if (myHeader = [self getMachHeader]) {
  394.     numHeaders = 1;
  395.     for (i = 0, loadCmd = (struct fvmlib_command *)(myHeader + 1);
  396.          i < myHeader->ncmds;
  397.          i++,
  398.          loadCmd = ((void *)loadCmd + loadCmd->cmdsize)) {
  399.         if (loadCmd->cmd == LC_LOADFVMLIB)
  400.         numHeaders++;
  401.     }
  402.     } else
  403.     numHeaders = 0;
  404.     return numHeaders;
  405. }
  406.  
  407. -(struct mach_header **)getMachHeadersWithNames: (char ***)names
  408. {
  409.     struct mach_header *myHeader, **headers, *header;
  410.     char **theNames = NULL;
  411.     struct fvmlib_command *loadCmd;
  412.     int numHeaders, headerIndex;
  413.     numHeaders = [self getNumMachHeaders];
  414.     myHeader = [self getMachHeader];
  415.     headers = malloc((numHeaders + 1) * sizeof(*headers));
  416.     if (names) {
  417.     *names = theNames = malloc((numHeaders + 1) * sizeof(*theNames));
  418.     theNames[0] = NULL;
  419.     }
  420.     headers[0] = myHeader;
  421.     for (headerIndex = 1, loadCmd = (struct fvmlib_command *)(myHeader + 1); 
  422.      headerIndex < numHeaders;
  423.      loadCmd = ((void *)loadCmd + loadCmd->cmdsize)) {
  424.     if (loadCmd->cmd == LC_LOADFVMLIB) {
  425.         header = [self pointerFor: (void *)(loadCmd->fvmlib.header_addr) 
  426.                          withSize: sizeof(*header)];
  427.         if (header)
  428.         headers[headerIndex]
  429.         = [self pointerFor: (void *)(loadCmd->fvmlib.header_addr)
  430.                       withSize: header->sizeofcmds];
  431.         if (names)
  432.         theNames[headerIndex]
  433.         = (char *)loadCmd
  434.                 + ((struct fvmlib_command *)loadCmd)
  435.                 ->fvmlib.name.offset; 
  436.         headerIndex++;
  437.     }
  438.     }
  439.     headers[numHeaders] = NULL;
  440.     if (names)
  441.     theNames[numHeaders] = NULL;
  442.     return headers;
  443. }
  444.  
  445. -(struct mach_header **)getMachHeaders
  446. {
  447.     return [self getMachHeadersWithNames: NULL];
  448. }
  449.  
  450. @end